#include "Model.h"

Model::Model() :
	pTextureRV(0)
{
	pVertexBuffer = 0;
	pIndexBuffer = 0;
	pFace = 0;
    pMesh = 0;
}

Model::~Model()
{
	Shutdown();
    SafeRelease(pMesh);
}

bool Model::Initialize(ID3D10Device* device, WCHAR* textureFilename,
		char* modelFilename)
{
	bool result;

	// Load in the model data.
	result = LoadModel(modelFilename);
	if (!result)
	{
		return false;
	}

	// Initialize the vertex and index buffer that hold the geometry for the triangle.
	result = InitializeBuffers(device);
	if (!result)
	{
		return false;
	}

	// Load the texture for this model.
	result = LoadTexture(device, textureFilename);
	if (!result)
	{
		return false;
	}

	return true;
}

void Model::Shutdown()
{
	// Release the model texture.
	ReleaseTexture();

	// Release the vertex and index buffers.
	ShutdownBuffers();

	// Release the model data.
	ReleaseModel();

	return;
}

void Model::Render(ID3D10Device* device)
{
	// Put the vertex and index buffers on the graphics pipeline to prepare them for drawing.
	RenderBuffers(device);

	return;
}

int Model::GetIndexCount()
{
	return nIndexCount;
}

ID3D10ShaderResourceView* Model::GetTexture()
{
	return pTextureRV;
}

bool Model::InitializeBuffers(ID3D10Device* device)
{
	Vertex* vertices;
	unsigned long* indices;
	D3D10_BUFFER_DESC vertexBufferDesc, indexBufferDesc;
	D3D10_SUBRESOURCE_DATA vertexData, indexData;
	HRESULT result;
	int i;

	// Create the vertex array.
	vertices = new Vertex[nVertexCount];
	if (!vertices)
	{
		return false;
	}

	// Create the index array.
	indices = new unsigned long[nIndexCount];
	if (!indices)
	{
		return false;
	}

	// Load the vertex array and index array with data.
	for (i = 0; i < nVertexCount; i++)
	{
		vertices[i].position = D3DXVECTOR3(pFace[i].x, pFace[i].y, pFace[i].z);
		vertices[i].texture = D3DXVECTOR2(pFace[i].tu, pFace[i].tv);
		vertices[i].normal = D3DXVECTOR3(pFace[i].nx, pFace[i].ny, pFace[i].nz);

		indices[i] = i;
	}

	// Set up the description of the vertex buffer.
	vertexBufferDesc.Usage = D3D10_USAGE_DEFAULT;
	vertexBufferDesc.ByteWidth = sizeof(Vertex) * nVertexCount;
	vertexBufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	vertexBufferDesc.CPUAccessFlags = 0;
	vertexBufferDesc.MiscFlags = 0;

	// Give the subresource structure a pointer to the vertex data.
	vertexData.pSysMem = vertices;

	// Now finally create the vertex buffer.
	result = device->CreateBuffer(&vertexBufferDesc, &vertexData,
			&pVertexBuffer);
	if (FAILED(result))
	{
		return false;
	}

	// Set up the description of the index buffer.
	indexBufferDesc.Usage = D3D10_USAGE_DEFAULT;
	indexBufferDesc.ByteWidth = sizeof(unsigned long) * nIndexCount;
	indexBufferDesc.BindFlags = D3D10_BIND_INDEX_BUFFER;
	indexBufferDesc.CPUAccessFlags = 0;
	indexBufferDesc.MiscFlags = 0;

	// Give the subresource structure a pointer to the index data.
	indexData.pSysMem = indices;

	// Create the index buffer.
	result = device->CreateBuffer(&indexBufferDesc, &indexData, &pIndexBuffer);
	if (FAILED(result))
	{
		return false;
	}


	// Release the arrays now that the vertex and index buffers have been created and loaded.
	delete[] vertices;
	vertices = 0;

	delete[] indices;
	indices = 0;

	return true;
}

void Model::ShutdownBuffers()
{
	// Release the index buffer.
	if (pIndexBuffer)
	{
		pIndexBuffer->Release();
		pIndexBuffer = 0;
	}

	// Release the vertex buffer.
	if (pVertexBuffer)
	{
		pVertexBuffer->Release();
		pVertexBuffer = 0;
	}

	return;
}

void Model::RenderBuffers(ID3D10Device* device)
{
	unsigned int stride;
	unsigned int offset;

	// Set vertex buffer stride and offset.
	stride = sizeof(Vertex);
	offset = 0;

	// Set the vertex buffer to active in the input assembler so it can be rendered.
	device->IASetVertexBuffers(0, 1, &pVertexBuffer, &stride, &offset);

	// Set the index buffer to active in the input assembler so it can be rendered.
	device->IASetIndexBuffer(pIndexBuffer, DXGI_FORMAT_R32_UINT, 0);

	// Set the type of primitive that should be rendered from this vertex buffer, in this case triangles.
	device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	return;
}

bool Model::LoadTexture(ID3D10Device* pDevice, WCHAR* filename)
{
	HRESULT hr = D3DX10CreateShaderResourceViewFromFile(pDevice, filename,
			NULL, NULL, &pTextureRV, NULL);
	if (FAILED(hr))
		return Error(L"Could not load texture file");

	return true;
}

void Model::ReleaseTexture()
{
	SafeRelease(pTextureRV);
}

bool Model::LoadModel(char* filename)
{
	ifstream fin;
	char input;
	int i;

	// Open the model file.  If it could not open the file then exit.
	fin.open(filename);
	if (fin.fail())
	{
		return false;
	}

	// Read up to the value of vertex count.
	fin.get(input);
	while (input != ':')
	{
		fin.get(input);
	}

	// Read in the vertex count.
	fin >> nVertexCount;

	// Set the number of indices to be the same as the vertex count.
	nIndexCount = nVertexCount;

	// Create the model using the vertex count that was read in.
	pFace = new Face[nVertexCount];
	if (!pFace)
	{
		return false;
	}

	// Read up to the beginning of the data.
	fin.get(input);
	while (input != ':')
	{
		fin.get(input);
	}
	fin.get(input);
	fin.get(input);

	// Read in the vertex data.
	for (i = 0; i < nVertexCount; i++)
	{
		fin >> pFace[i].x >> pFace[i].y >> pFace[i].z;
		fin >> pFace[i].tu >> pFace[i].tv;
		fin >> pFace[i].nx >> pFace[i].ny >> pFace[i].nz;
	}

	// Close the model file.
	fin.close();

	return true;
}

void Model::ReleaseModel()
{
	if (pFace)
	{
		delete[] pFace;
		pFace = 0;
	}

	return;
}
